package net.xxcxcxcx.xc_enhancedmob.entity;

import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.projectile.AbstractFireballEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.Packet;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion;
import net.xxcxcxcx.xc_enhancedmob.EnhancedMobMod;
import net.xxcxcxcx.xc_enhancedmob.packet.CustomEntitySpawnPacket;
import net.xxcxcxcx.xc_enhancedmob.register.EntityRegister;

import java.util.OptionalInt;

public class SaveFireballEntity extends AbstractFireballEntity {
    private static final TrackedData<OptionalInt> Target_ENTITY_ID = DataTracker.registerData(SaveFireballEntity.class, TrackedDataHandlerRegistry.FIREWORK_DATA);
    public int explosionPower = 1;
    public float hitDamage = 6.0f;
    public Entity toTarget = null;

    public SaveFireballEntity(EntityType<SaveFireballEntity> entityType, World world) {
        super(entityType, world);
    }

    @Environment(value = EnvType.CLIENT)
    public SaveFireballEntity(World world, double x, double y, double z, double velocityX, double velocityY, double velocityZ) {
        super(EntityRegister.SaveFireballEntityType, x, y, z, velocityX, velocityY, velocityZ, world);
    }

    public SaveFireballEntity(World world, LivingEntity owner, double velocityX, double velocityY, double velocityZ, Entity totarget) {
        super(EntityRegister.SaveFireballEntityType, owner, velocityX, velocityY, velocityZ, world);
        if (totarget != null) this.dataTracker.set(Target_ENTITY_ID, OptionalInt.of(totarget.getEntityId()));
        toTarget = totarget;
    }

    @Override
    protected void onCollision(HitResult hitResult) {
        super.onCollision(hitResult);
        if (!this.world.isClient) {
            this.world.createExplosion(this.getOwner(), DamageSource.fireball(this, this.getOwner()), null, this.getX(), this.getY(), this.getZ(), this.explosionPower, true, Explosion.DestructionType.NONE);
            this.remove();
        }
    }

    @Override
    public boolean damage(DamageSource source, float amount) {
        if (this.isInvulnerableTo(source)) {
            return false;
        }
        this.scheduleVelocityUpdate();
        Entity entity = source.getAttacker();
        if (entity != null && entity != this.getOwner()) {
            Vec3d vec3d = entity.getRotationVector();
            this.setVelocity(vec3d);
            this.powerX = vec3d.x * 0.1;
            this.powerY = vec3d.y * 0.1;
            this.powerZ = vec3d.z * 0.1;
            if (this.toTarget != null) this.toTarget = this.getOwner();
            this.setOwner(entity);
            if (this.toTarget != null && !this.world.isClient)
                this.dataTracker.set(Target_ENTITY_ID, OptionalInt.of(toTarget.getEntityId()));
            return true;
        }
        return false;
    }

    @Override
    protected void onEntityHit(EntityHitResult entityHitResult) {
        super.onEntityHit(entityHitResult);
        if (this.world.isClient) {
            return;
        }
        Entity entity = entityHitResult.getEntity();
        Entity entity2 = this.getOwner();
        entity.damage(DamageSource.fireball(this, entity2), hitDamage);
        if (entity2 instanceof LivingEntity) {
            this.dealDamage((LivingEntity) entity2, entity);
        }
    }

    @Override
    protected void initDataTracker() {
        super.initDataTracker();
        this.dataTracker.startTracking(Target_ENTITY_ID, OptionalInt.empty());
    }

    @Override
    public void writeCustomDataToNbt(NbtCompound nbt) {
        super.writeCustomDataToNbt(nbt);
        nbt.putInt("ExplosionPower", this.explosionPower);
        nbt.putInt("Target_ENTITY_ID", this.dataTracker.get(Target_ENTITY_ID).orElse(-1) + 1);
    }

    @Override
    public void readCustomDataFromNbt(NbtCompound nbt) {
        super.readCustomDataFromNbt(nbt);
        if (nbt.contains("ExplosionPower", 99)) {
            this.explosionPower = nbt.getInt("ExplosionPower");
        }
        if (nbt.contains("TargetEntityId")) {
            this.dataTracker.set(Target_ENTITY_ID, nbt.getInt("TargetEntityId") == 0 ? OptionalInt.empty() : OptionalInt.of(nbt.getInt("TargetEntityId") - 1));
        }
    }

    @Override
    public void tick() {
        super.tick();
        if (this.toTarget == null) {
            this.dataTracker.get(Target_ENTITY_ID).ifPresent(i -> {
                Entity entity = this.world.getEntityById(i);
                if (entity instanceof LivingEntity) {
                    this.toTarget = entity;
                }
            });
        }
        if (toTarget != null) {
            double directionX = toTarget.getX() - (this.getX());
            double directionY = toTarget.getBodyY(0.5) - (0.5 + this.getBodyY(1.5));
            double directionZ = toTarget.getZ() - (this.getZ());
            double d = MathHelper.sqrt(directionX * directionX + directionY * directionY + directionZ * directionZ);
            if (d != 0.0) {
                this.powerX = directionX / d * 0.1;
                this.powerY = directionY / d * 0.1;
                this.powerZ = directionZ / d * 0.1;
                Vec3d vec3d1 = new Vec3d(this.powerX, this.powerY, this.powerZ);
                Vec3d vec3d2 = this.getVelocity();
                double length = vec3d2.length() / vec3d1.length();
                this.setVelocity(vec3d1.multiply(length));
            }
        }
    }

    @Override
    public Packet<?> createSpawnPacket() {
        Entity entity = this.getOwner();
        int i = entity == null ? 0 : entity.getEntityId();
        return CustomEntitySpawnPacket.creat(this.getEntityId(), this.getUuid(), this.getX(), this.getY(), this.getZ(), this.pitch, this.yaw, this.getType(), i, new Vec3d(this.powerX, this.powerY, this.powerZ), EnhancedMobMod.CustomEntityIdentifier);
    }
}
